﻿// --------------------------------------------------------------------------------------
// 	文 件 名: shSerializer.h
// --------------------------------------------------------------------------------------
// 	创建时间: 2021/12/07
// 	版　　本: Version:  1.0.0
// 	版    权: Copyright (C) 2007 - 2021 NUCTECH All Rights Reserved
// 	作    者: chenyu
// --------------------------------------------------------------------------------------
// 	说    明: MTS - 序列化（用于C++ <==> C#互转）。
// --------------------------------------------------------------------------------------
// 	修改历史:
// 			日期							改动
//		2021.12.07						  创建模块
// --------------------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Reflection.Metadata;
using System.Text;

namespace SH
{

    [Flags]
    public enum emReadWriteType
    {
        emRWT_Invalid = 0,
        emRWT_Read = 1,
        emRWT_Write = 2,

    };

    public interface shISerializeable
    {
        abstract shISerializer serialize(shISerializer sc);

    }


    public interface shISerializer
    {
        public bool isRead();

        public bool isWrite();

        public shISerializer Read(ref byte[] data, ref long len);

        public shISerializer Write(byte[] data, long len);

        public shISerializer serialize(ref byte v);

        public shISerializer serialize(ref byte[] v);

        public shISerializer serialize(ref sbyte v);
        public shISerializer serialize(ref short v);

        public shISerializer serialize(ref ushort v);
        public shISerializer serialize(ref int v);
        public shISerializer serialize(ref uint v);

        public shISerializer serialize(ref long v);

        public shISerializer serialize(ref ulong v);

        public shISerializer serialize(ref float v);

        public shISerializer serialize(ref double v);
        public shISerializer serialize(ref string v);

        public shISerializer serialize(ref char v);
        public shISerializer serialize(HashSet<string> v);
        public shISerializer serialize(ref List<string> v);

        public shISerializer serialize<T>(ref T v) where T : struct;

        public shISerializer serialize<T>(ref HashSet<T> v) where T : struct;

        public shISerializer serialize<T>(HashSet<T> v) where T : shISerializeable, new();

        public shISerializer serialize<T>(ref List<T> v) where T : struct;


        public shISerializer serialize<T>(List<T> v) where T : shISerializeable, new();

        public shISerializer serialize<K, V>(ref Dictionary<K, V> v) where K : shISerializeable, new() where V : shISerializeable, new();

        public shISerializer serialize<T>(T v) where T : shISerializeable;


    }


    public class shSerializer : shISerializer
    {

        protected emReadWriteType m_rwt;

        protected System.IO.BinaryWriter m_writer;

        protected System.IO.BinaryReader m_reader;

        public shSerializer()
        {
            m_rwt = emReadWriteType.emRWT_Invalid;
        }
        public shSerializer(emReadWriteType rwt)
        {
            m_rwt = rwt;
        }
        public shSerializer(shSerializer other)
        {
            m_rwt = other.m_rwt;
            other.m_rwt = emReadWriteType.emRWT_Invalid;
        }

        public bool isRead()
        {
            return (m_rwt & emReadWriteType.emRWT_Read) == emReadWriteType.emRWT_Read;
        }

        public bool isWrite()
        {
            return (m_rwt & emReadWriteType.emRWT_Write) == emReadWriteType.emRWT_Write;
        }

        public shISerializer Read(ref byte[] data,ref long len)
        {
            if (isRead())
            {
                len = m_reader.ReadInt64();

                if (len != 0)
                {
                    data = m_reader.ReadBytes((int)len);
                
                }
               
            }

            return this;
        }
        public shISerializer Write(byte[] data, long len)
        {
            if(isWrite())
            {
                long nLen = 0;

                if (data != null)
                {
                    nLen = Math.Min(len, data.Length);
                }

                m_writer.Write(nLen);

                if (nLen != 0 )
                {
                    m_writer.Write(data, 0, (int)nLen);
                }
                  
            }

            return this;
        }


        public shISerializer serialize(ref byte v)
        {
            if (isRead())
            {
                v = m_reader.ReadByte();
            }
            else
            {
                m_writer.Write(v);
            }

            return this;
        }

        public shISerializer serialize(ref byte[] v)
        {
            if (isRead())
            {
                long nCount = m_reader.ReadInt64();

                if(nCount != 0)
                v = m_reader.ReadBytes((int)nCount);
            }
            else
            {
                long nCount = v== null? 0: v.Length;

                m_writer.Write(nCount);

                if (nCount != 0)
                    m_writer.Write(v);
            }

            return this;
        }


        public shISerializer serialize(ref sbyte v)
        {

            if (isRead())
            {
                v = m_reader.ReadSByte();
            }
            else
            {
                m_writer.Write(v);
            }

            return this;
        }

        public shISerializer serialize(ref short v)
        {

            if (isRead())
            {
                v = m_reader.ReadInt16();
            }
            else
            {
                m_writer.Write(v);
            }

            return this;
        }

        public shISerializer serialize(ref ushort v)
        {

            if (isRead())
            {
                v = m_reader.ReadUInt16();
            }
            else
            {
                m_writer.Write(v);
            }

            return this;
        }

        public shISerializer serialize(ref int v)
        {

            if (isRead())
            {
                v = m_reader.ReadInt32();
            }
            else
            {
                m_writer.Write(v);
            }

            return this;
        }
        public shISerializer serialize(ref uint v)
        {
            if (isRead())
            {
                v = m_reader.ReadUInt32();
            }
            else
            {
                m_writer.Write(v);
            }

            return this;
        }

        public shISerializer serialize(ref long v)
        {
            if (isRead())
            {
                v = m_reader.ReadInt64();
            }
            else
            {
                m_writer.Write(v);
            }

            return this;
        }

        public shISerializer serialize(ref ulong v)
        {
            if (isRead())
            {
                v = m_reader.ReadUInt64();
            }
            else
            {
                m_writer.Write(v);
            }

            return this;
        }

        public shISerializer serialize(ref float v)
        {
            if (isRead())
            {
                v = m_reader.ReadSingle();
            }
            else
            {
                m_writer.Write(v);
            }

            return this;
        }

        public shISerializer serialize(ref double v)
        {
            if (isRead())
            {
                v = m_reader.ReadDouble();
            }
            else
            {
                m_writer.Write(v);
            }

            return this;
        }
        public shISerializer serialize(ref char v)
        {
            if (isRead())
            {
                v = m_reader.ReadChar();
            }
            else
            {
                m_writer.Write(v);
            }

            return this;
        }
        public shISerializer serialize(ref char[] v)
        {
            if (isRead())
            {
                long nCount = m_reader.ReadInt64();

                if (nCount != 0)
                {
                    byte[] byteArray = m_reader.ReadBytes((int)nCount);
                    v = System.Text.Encoding.Default.GetChars(byteArray);
                }
                   
            }
            else
            {
                long nCount = v == null ? 0 : v.Length;
                if (nCount != 0)
                {
                    byte[] byteArray = System.Text.Encoding.UTF8.GetBytes(v);
                    nCount = byteArray.Length;
                    m_writer.Write(nCount);
                    m_writer.Write(byteArray);
                }
                else
                    m_writer.Write(nCount);
            }

            return this;
        }

        public shISerializer serialize(ref string v)
        {
            if (isRead())
            {
                long nCount = m_reader.ReadInt64();

                if (nCount != 0)
                {
                    byte[] byteArray = m_reader.ReadBytes((int)nCount);
                    v = System.Text.Encoding.Default.GetString(byteArray);
                }
                else
                    v = "";
            }
            else
            {
                long nCount = v == null? 0: v.Length;

                if (nCount != 0)
                {
                    byte[] byteArray = System.Text.Encoding.UTF8.GetBytes(v);
                    nCount = byteArray.Length;
                    m_writer.Write(nCount);
                    m_writer.Write(byteArray);
                }
                else
                    m_writer.Write(nCount);

            }

            return this;
        }

        public shISerializer serialize(ref List<string> v)
        {
            if (isRead())
            {
                long nCount = m_reader.ReadInt64();

                if (nCount != 0)
                {
                    if (v == null)
                        v = new List<string>();

                    for (var n = 0; n < nCount; ++n)
                    {
                        string x = "";

                        serialize(ref x);

                        v.Add(x);
                    }
                }
            }
            else
            {
                long nCount = v == null ? 0 : v.Count;

                m_writer.Write(nCount);

                if (nCount != 0)
                {
                    foreach (var n in v)
                    {
                        write(n);
                    }
                }
            }
            return this;
        }
        public shISerializer serialize(HashSet<string> v)
        {
            if (isRead())
            {
                long nCount = m_reader.ReadInt64();

                if (nCount != 0)
                {
                    if (v == null)
                        v = new HashSet<string>();

                    for (var n = 0; n < nCount; ++n)
                    {
                        string x = "";

                        serialize(ref x);

                        v.Add(x);
                    }
                }
            }
            else
            {
                long nCount = v == null ? 0 : v.Count;

                m_writer.Write(nCount);

                if (nCount != 0)
                {
                    foreach (var n in v)
                    {
                        write(n);
                    }
                }
            }

            return this;
        }


        public shISerializer serialize<T>(ref T v) where T : struct
        {

            var type = v.GetType();

            if (type.IsPrimitive)
            {
                if (isRead())
                {
                    dynamic a = v;

                    if (a is int)
                    {
                        a = m_reader.ReadInt32();
                    }
                    else if (a is uint)
                    {
                        a = m_reader.ReadUInt32();
                    }
                    else if (a is ushort)
                    {
                        a = m_reader.ReadUInt16();
                    }
                    else if (a is short)
                    {
                        a = m_reader.ReadInt16();
                    }
                    else if (a is long)
                    {
                        a = m_reader.ReadInt64();
                    }
                    else if (a is ulong)
                    {
                        a = m_reader.ReadUInt64();
                    }
                    else if (a is float)
                    {
                        a = m_reader.ReadSingle();
                    }
                    else if (a is double)
                    {
                        a = m_reader.ReadDouble();
                    }
                    else if (a is sbyte)
                    {
                        a = m_reader.ReadSByte();
                    }
                    else if (a is byte)
                    {
                        a = m_reader.ReadByte();
                    }
                    else if(a is bool)
                    {
                        a = m_reader.ReadBoolean();
                    }

                    v = a;
                }
                else
                {
                    dynamic a = v;

                    m_writer.Write(a);
                }
            }
            else if (type.IsEnum)
            {
                if (isRead())
                {
                    dynamic b = v;
                    int a = m_reader.ReadInt32();

                    b = a;

                    v = (T)b;
                }
                else if (isWrite())
                {
                    dynamic b = v;

                    m_writer.Write((int)b);
                }
            }

            return this;
        }

        public shISerializer serialize<T>(T v) where T : shISerializeable
        {
            v.serialize(this);

            return this;
        }


        public shSerializer write(byte v)
        {
            if (isWrite())
            {
                m_writer.Write(v);
            }

            return this;
        }

        public shSerializer write(sbyte v)
        {

            if (isWrite())
            {
                m_writer.Write(v);
            }

            return this;
        }

        public shSerializer write(short v)
        {

            if (isWrite())
            {
                m_writer.Write(v);
            }

            return this;
        }

        public shSerializer write(ushort v)
        {

            if (isWrite())
            {
                m_writer.Write(v);
            }

            return this;
        }

        public shSerializer write(int v)
        {
            if (isWrite())
            {
                m_writer.Write(v);
            }
            return this;
        }

        public shSerializer write(uint v)
        {
            if (isWrite())
            {
                m_writer.Write(v);
            }
            return this;
        }

        public shSerializer write(long v)
        {
            if (isWrite())
            {
                m_writer.Write(v);
            }

            return this;
        }

        public shSerializer write(ulong v)
        {
            if (isWrite())
            {
                m_writer.Write(v);
            }

            return this;
        }

        public shSerializer write(float v)
        {
            if (isWrite())
            {
                m_writer.Write(v);
            }

            return this;
        }

        public shSerializer write(double v)
        {
            if (isWrite())
            {
                m_writer.Write(v);
            }

            return this;
        }

        public shSerializer write(string v)
        {
            if (isWrite())
            {
                long nCount = v == null? 0 : v.Length;

                if(nCount > 0)
                {
                    byte[] byteArray = System.Text.Encoding.UTF8.GetBytes(v);
                    nCount = byteArray.Length;
                    m_writer.Write(nCount);
                    m_writer.Write(byteArray);
                }
                else
                    m_writer.Write(nCount);
            }

            return this;
        }

        public shSerializer write(char v)
        {
            if (isWrite())
            {
                m_writer.Write(v);
            }

            return this;
        }

        public shSerializer write<T>(T v) where T : struct
        {

            var type = v.GetType();

            if (type.IsPrimitive)
            {
                if (isWrite())
                {
                    dynamic a = v;

                    m_writer.Write(a);
                }
            }
            else if (type.IsEnum)
            {
                if (isWrite())
                {
                    dynamic b = v;

                    m_writer.Write((int)b);
                }
            }

            return this;
        }

        public shISerializer serialize<T>(ref HashSet<T> v) where T : struct
        {
            if (isRead())
            {
                long nCount = m_reader.ReadInt64();

                if (nCount != 0)
                {
                    if(v == null)
                        v = new HashSet<T>();

                    for (var n = 0; n < nCount; ++n)
                    {
                        T x = new T();

                        serialize(ref x);

                        v.Add(x);
                    }
                }
            }
            else
            {
                long nCount = v == null ? 0 : v.Count;

                m_writer.Write(nCount);

                if (nCount != 0)
                {
                    foreach (var n in v)
                    {
                        write(n);
                    }
                }
            }

            return this;
        }

        public shISerializer serialize<T>(HashSet<T> v) where T : shISerializeable, new()
        {
            if (isRead())
            {
                long nCount = m_reader.ReadInt64();

                if (nCount != 0)
                {
                    if (v == null)
                        v = new HashSet<T>();

                    for (var n = 0; n < nCount; ++n)
                    {
                        T x = new T();

                        serialize(x);

                        v.Add(x);
                    }

                }
            }
            else
            {
                long nCount = v == null ? 0 : v.Count;

                m_writer.Write(nCount);

                if (nCount != 0)
                {
                    foreach (var n in v)
                    {
                        serialize(n);
                    }
                }
            }

            return this;
        }

        public shISerializer serialize<T>(ref List<T> v) where T : struct
        {
            if (isRead())
            {
                long nCount = m_reader.ReadInt64();

                if (nCount != 0)
                {
                    if (v == null)
                        v = new List<T>();

                    for (var n = 0; n < nCount; ++n)
                    {
                        T x = new T();

                        serialize(ref x);

                        v.Add(x);
                    }
                }
            }
            else
            {
                long nCount = v == null ? 0 : v.Count;

                m_writer.Write(nCount);

                if (nCount != 0)
                {
                    foreach (var n in v)
                    {
                        write(n);
                    }
                }
            }

            return this;
        }

        public shISerializer serialize<T>(List<T> v) where T : shISerializeable, new()
        {
            if (isRead())
            {
                long nCount = m_reader.ReadInt64();

                if (nCount != 0)
                {
                    if (v == null)
                        v = new List<T>();

                    for (var n = 0; n < nCount; ++n)
                    {
                        T x = new T();

                        serialize(x);

                        v.Add(x);
                    }

                }
            }
            else
            {
                long nCount = v == null ? 0 : v.Count;

                m_writer.Write(nCount);

                if (nCount != 0)
                {
                    foreach (var n in v)
                    {
                        serialize(n);
                    }
                }
            }

            return this;
        }

        public shISerializer serialize<K, V>(ref Dictionary<K, V> v) where K : shISerializeable, new() where V : shISerializeable, new()
        {
            if (isRead())
            {
                long nCount = m_reader.ReadInt64();

                if (nCount != 0)
                {
                    if (v == null)
                        v = new Dictionary<K, V>();

                    for (var n = 0; n < nCount; ++n)
                    {
                        K k = new K();
                        V x = new V();
                        serialize(k);
                        serialize(x);

                        v.Add(k,x);
                    }

                }
            }
            else
            {
                long nCount = v == null ? 0 : v.Count;

                m_writer.Write(nCount);

                if (nCount != 0)
                {
                    foreach (var n in v)
                    {
                        serialize(n.Key);
                        serialize(n.Value);

                    }
                }
            }

            return this;
        }


        //public shSerializer serialize(shISerializer sc)
        //{
        //    // v.serialize(this);
        //   return sc.serialize(this);

        //}

    };


}
